package ni;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

/**
 * TCPReceiver_1 is used to receive a file from a remoteUser. It is replacing
 * the TCPReceiver class that was managing the file proposal, proposing the file
 * to the local user on this thread's time, and answering the remote user with
 * the right Signal. Contrary to the TCPReceiver class, this class is only
 * accepting a connection from a remote User and receiving the file that it
 * writes straight away on the disk, inside the Download folder.
 *
 * @author gb
 */
public class TCPReceiver_1 extends Thread {

    private ServerSocket srvsock;
    private Socket clientsock;
    private ChatNI chatNI;
    private String filename;
    private long fileSize;
    private String remoteNetname;
    private ArrayList<String> to;

    /**
     * Creates a TCPReceiver_1 object
     *
     * @param chatNI needed to give a simple feedback on the reception
     * @param filename needed to write the file on the disk
     * @param fileSize needed to know when to stop the reception
     * @param remoteNetname needed to give a simple feedback on the reception
     * @param to needed to give a simple feedback on the reception
     */
    public TCPReceiver_1(ChatNI chatNI, String filename, long fileSize, String remoteNetname, ArrayList<String> to) {
        this.chatNI = chatNI;
        this.filename = filename;
        this.fileSize = fileSize;
        this.remoteNetname = remoteNetname;
        this.to = to;
    }

    /**
     * Starts a server on the ChatNI receivePort, accepts the connection from
     * the remote file sender, receives the file and writes it in the Download
     * folder, advices chat ni on the file reception, advices chat ni it is
     * closing
     */
    @Override
    public void run() {
        try {
            srvsock = new ServerSocket(ChatNI.receivePort);
        } catch (IOException ex) {
            System.err.println("In TCPReceiver - run : could not open the server.");
        }
        InputStream is = null;
        clientsock = null;
        try {
            clientsock = srvsock.accept();
        } catch (IOException ex) {
            System.err.println("In TCPReceiver - run : could not accept connection from the remote client.");
        }

        try {
            is = clientsock.getInputStream();
        } catch (IOException ex) {
            System.err.println("In TCPReceiver - run : could not get the input stream.");
        }

        readingInputIntoFile(is, (int) fileSize, filename);

        chatNI.processFileReception(filename, remoteNetname, to, true);

        try {
            clientsock.close();
            srvsock.close();
        } catch (IOException ex) {
            System.err.println("In TCPReceiver - run : could not close the socket.");
        }

        chatNI.processReceiverThreadClosure(this);
    }

    /**
     * Writes an input stream in a file Reads exactly fileSize bytes.
     *
     * @param is The inputstream
     * @param fileSize The size of the file
     * @param fileName The name of the file
     */
    public static void readingInputIntoFile(InputStream is, int fileSize, String fileName) {
        FileOutputStream fos = null;
        ChatNI.printDebug("TCP_Receiver", "readingInputIntoFile", "Preparing to receive the file : " + fileName + " of " + fileSize + " bytes.");

        try {
            fos = new FileOutputStream("Download/" + fileName);
        } catch (FileNotFoundException ex) {
            System.err.println("In TCP_Receiver - readingInputIntoFile : could not find the file. ");
        }

        int bytesRead;
        int count = 0;

        try {
            do {
                byte[] bytes = new byte[1024];
                bytesRead = is.read(bytes);
                count += bytesRead;
                //ChatNI.printDebug("TCP_Receiver", "readingInputIntoFile", "Received " + bytesRead + " bytes.");
                fos.write(bytes, 0, bytesRead);
                //ChatNI.printDebug("TCP_Receiver", "readingInputIntoFile", "Wrote " + bytesRead + " bytes.");
            } while (count < fileSize);
            ChatNI.printDebug("TCP_Receiver", "readingInputIntoFile", "Wrote " + count + " bytes in total.");
            fos.flush();
            fos.close();
        } catch (IOException ex) {
            System.err.println("In TCP_Receiver - readingInputIntoFile : could not read the b.i.s or write into the b.o.s. ");
        }
    }

    /**
     * Closes the client and server sockets this cuts the current file transfer
     */
    public void closeSockets() {
        try {
            this.clientsock.close();
        } catch (IOException ex) {
            System.err.println("In TCP_Receiver - readingInputIntoFile : could not close the client connected Socket ");
        }
        try {
            this.srvsock.close();
        } catch (IOException ex) {
            System.err.println("In TCP_Receiver - closeSockets : could not close serverSocket ");
        }
    }
}
